package gqz.testdemo.BtBleDemo;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;

import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale;

import gqz.testdemo.Bluetooth.BleServer;
import gqz.testdemo.R;

/**
 * Created by Administrator on 2018/9/18.
 */

public class BleClientDemo extends Activity implements View.OnClickListener {
    private static final String TAG = "BleClientDemo-->";
    public static final int REQUEST_BT_ENABLE_CODE = 200;

    private BluetoothAdapter mBluetoothAdapter;//蓝牙适配器
    private MyLeScanCallback1 mLeScanCallback1;//搜索回调1
    private MyLeScanCallback2 mLeScanCallback2;//搜索回调2

    private BluetoothGatt mBluetoothGatt;//GATT客户端
    private BluetoothLeScanner mBleScanner;//BLE扫描器
    private boolean mScanning;//是否正在搜索
    private RecyclerView devicesView, msgsView;
    private RvAdapter mDeviceAdapter;
    private MsgAdapter mMessageAdapter;
    private List<BluetoothGattService> mServiceList;//服务列表

    private SimpleDateFormat mDateFormat;
    private boolean isCallback1 = true;

    private Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case 0:
                    mMessageAdapter.addMessage(mDateFormat.format(System.currentTimeMillis()) + "  " + msg.getData().getString("msg"));
                    break;
            }
            return false;
        }
    });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ble_main);
        mDateFormat = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
        initUI();
        initList();

        IntentFilter i = new IntentFilter();
        i.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        i.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
        i.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
        i.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        i.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
        i.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        registerReceiver(receiver, i);
    }

    private void outputLog(String msg) {
        if (mMessageAdapter != null) {
            Message message = new Message();
            message.what = 0;
            Bundle bundle = new Bundle();
            bundle.putString("msg", msg);
            message.setData(bundle);
            mHandler.sendMessage(message);
            Log.d(TAG, "outputLog: " + msg);
        }
    }

    private void initUI() {
        findViewById(R.id.open).setOnClickListener(this);
        findViewById(R.id.close).setOnClickListener(this);
        findViewById(R.id.start).setOnClickListener(this);
        findViewById(R.id.stop).setOnClickListener(this);
        findViewById(R.id.mtu).setOnClickListener(this);
//        findViewById(R.id.callback_type).setOnClickListener(this);


        mLeScanCallback1 = new MyLeScanCallback1();
        mLeScanCallback2 = new MyLeScanCallback2();
    }

    private void initList() {

        mDeviceAdapter = new RvAdapter(this);
        mMessageAdapter = new MsgAdapter(this);

        devicesView = (RecyclerView) findViewById(R.id.devices);
        devicesView.setLayoutManager(new LinearLayoutManager(this));
        devicesView.setAdapter(mDeviceAdapter);

        msgsView = (RecyclerView) findViewById(R.id.msglist);
        msgsView.setLayoutManager(new LinearLayoutManager(this));
        msgsView.setAdapter(mMessageAdapter);

        mDeviceAdapter.setOnItemClickListener(new RvAdapter.OnItemClickListener() {
            @Override
            public void onClick(BluetoothDevice device) {
                connectGatt(device);
            }
        });

    }

    BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            switch (intent.getAction()) {
                case BluetoothAdapter.ACTION_STATE_CHANGED:
                    int blueState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
                    switch (blueState) {
                        case BluetoothAdapter.STATE_TURNING_ON:
                            outputLog("蓝牙正在打开...");
//                            bleEnable = false;
                            break;
                        case BluetoothAdapter.STATE_ON:
                            outputLog("蓝牙已打开");
//                            bleEnable = true;
//                            getBleOpenStatus();
//                            switch_ble.setEnabled(true);
                            break;
                        case BluetoothAdapter.STATE_TURNING_OFF:
                            outputLog("蓝牙正在关闭...");
//                            bleEnable = false;
//                            getBleOpenStatus();
                            break;
                        case BluetoothAdapter.STATE_OFF:
                            outputLog("蓝牙已关闭");
//                            bleEnable = false;
//                            switch_ble.setEnabled(true);
                            break;
                    }
                    break;
                case BluetoothAdapter.ACTION_SCAN_MODE_CHANGED:
                    Log.i(TAG, "onReceive: scan mode changed");
//                    getAllowSearchStatus();
                    break;
                case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
                    Log.i(TAG, "onReceive: discovery started");
                    break;
                case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
                    Log.i(TAG, "onReceive: discovery finished");
                    break;
                case BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED:
                    Log.i(TAG, "onReceive: connection state changed");
                    break;
                case BluetoothDevice.ACTION_BOND_STATE_CHANGED:
                    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    switch (device.getBondState()) {
                        case BluetoothDevice.BOND_NONE:
                            Log.e(getPackageName(), "取消配对");
                            break;
                        case BluetoothDevice.BOND_BONDING:
                            Log.e(getPackageName(), "配对中");
                            break;
                        case BluetoothDevice.BOND_BONDED:
                            Log.e(getPackageName(), "配对成功");
                            break;
                    }
                    break;
            }
        }
    };

    private void connectGatt(BluetoothDevice device) {
        outputLog("正在连接到：" + device.getName());
        //新建一个链接
        mBluetoothGatt = device.connectGatt(BleClientDemo.this, false, mBluetoothGattCallback);
        //mBluetoothGatt.connect();//如果是断开重连
        //mBluetoothGatt.disconnect();//断开当前连接
    }

    private void openBT() {
        if (mBluetoothAdapter == null) {
            /**这里和传统的蓝牙有什么区别呢？*/
            final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
            mBluetoothAdapter = bluetoothManager.getAdapter();
            //mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            //如果调用scanBleDevices2()，请加上这句。 Call requires API level 21
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                mBleScanner = mBluetoothAdapter.getBluetoothLeScanner();
            }
        }
        //1.设备不支持蓝牙，结束应用
        if (mBluetoothAdapter == null) {
            finish();
            return;
        }
        //2.判断蓝牙是否打开
        if (!mBluetoothAdapter.enable()) {
            //没打开请求打开
            Intent btEnable = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(btEnable, REQUEST_BT_ENABLE_CODE);
            outputLog("正在打开蓝牙");
        }
    }

    private void scanBleDevices1(boolean enable) {
        if (enable) {
            outputLog("正在搜索设备");
            outputLog("当前搜索回调:callback 1");
            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    mBluetoothAdapter.stopLeScan(mLeScanCallback1);
                    outputLog("停止搜索");
                }
            }, 10000);//设置10秒超时
            mScanning = true;
            mBluetoothAdapter.startLeScan(mLeScanCallback1);
        } else {
            outputLog("停止搜索");
            mScanning = false;
            mBluetoothAdapter.stopLeScan(mLeScanCallback1);
        }
    }

    private void scanBleDevices2(boolean enable) {
        if (mBleScanner == null) {
            outputLog("搜索器初始化失败");
            return;
        }
        if (enable) {
            outputLog("当前搜索回调:callback 2");
            outputLog("正在搜索设备");
            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    mBleScanner.stopScan(mLeScanCallback2);
                    outputLog("停止搜索");
                }
            }, 10000);//设置10秒超时
            mScanning = true;
            mBleScanner.startScan(mLeScanCallback2);
        } else {
            mScanning = false;
            mBleScanner.stopScan(mLeScanCallback2);
            outputLog("停止搜索");
        }
    }

    /**
     * 找到自己想要获取的特性，并设置更改通知
     * 例如，服务里面提供了心率检测和血压监测，我现在只想获取心率
     */
    private void setCharacteristicNotification() {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        //找到对应服务
        BluetoothGattCharacteristic characteristic = null;
        for (BluetoothGattService s : mServiceList) {
            if (s.getUuid().equals(BleServer.TIME_SERVICE)) {
                //找到对应服务的特性
                List<BluetoothGattCharacteristic> cList = s.getCharacteristics();
                for (BluetoothGattCharacteristic c : cList) {
                    if (c.getUuid().equals(BleServer.CURRENT_TIME)) {
                        //找出需要通知改变的特性
                        characteristic = c;
                    }
                }
            }
        }
        if (characteristic == null) {
            return;//服务中不包含我们需要获取的特性
        }
        //启动通知：BLE应用程序通常在设备上的特定特性发生变化时要求收到通知
        //一旦为特性启用通知，如果远程设备上的特性发生变化，则触发回调onCharacteristicChanged()
        mBluetoothGatt.setCharacteristicNotification(characteristic, true);
        outputLog("开启特性变化通知成功");
        // This is specific to Heart Rate Measurement.
        //这里要对应我服务端所使用的UUID,详情请查看上一篇博客
        //更改特性描述
        if (BleServer.CURRENT_TIME.equals(characteristic.getUuid())) {
            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(BleServer.CLIENT_CONFIG);
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            mBluetoothGatt.writeDescriptor(descriptor);
        }

        //然后读一下这个特性
        mBluetoothGatt.readCharacteristic(characteristic);//会触发回调，这里就到回调中处理
    }

    //写特性，其他操作类似，直接使用mBluetoothGatt调用对应的方法即可
    private boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
        if (mBluetoothGatt != null) {
            return mBluetoothGatt.writeCharacteristic(characteristic);
        }
        return false;
    }

    /**
     * 关闭蓝牙或者退出应用别忘了关闭客户端哦
     */
    private void close() {
        if (mBluetoothGatt == null) {
            return;
        }
        mBluetoothGatt.close();
        mBluetoothGatt = null;
    }

    @Override
    protected void onDestroy() {
        close();
        super.onDestroy();
    }

    /**
     * GATT操作回调
     */
    private BluetoothGattCallback mBluetoothGattCallback = new BluetoothGattCallback() {
        @Override
        public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
            super.onPhyUpdate(gatt, txPhy, rxPhy, status);
        }

        @Override
        public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
            super.onPhyRead(gatt, txPhy, rxPhy, status);
        }

        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                //成功连接
                outputLog("连接蓝牙服务成功");
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mBluetoothGatt.discoverServices();//搜索服务器中的包含服务
                        outputLog("搜索外围服务");
                    }
                }, 3000);
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                //断开连接
                outputLog("断开蓝牙服务");
            } else {
                outputLog("");
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                outputLog("成功搜索到服务");
                //找到服务
                //获取服务列表
                mServiceList = gatt.getServices();
                //设置特性更改通知
                setCharacteristicNotification();
            } else {
                outputLog("服务搜索失败");
                Log.w(TAG, "onServicesDiscovered received: " + status);
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //读取特性
                //characteristic.getValue();
                outputLog("读取到特性：" + new String(characteristic.getValue()));
                msgsView.scrollToPosition(mMessageAdapter.getItemCount() - 1);
                int range = msgsView.computeVerticalScrollRange();
                int offset = msgsView.computeVerticalScrollOffset();
                int extent = msgsView.computeVerticalScrollExtent();
                msgsView.smoothScrollBy(0, offset + (range - offset - extent));
            }
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //反写成功
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            //服务端特性改变 读取新数据
            outputLog("接收到特性变化：" + new String(characteristic.getValue()));
            gatt.readCharacteristic(characteristic);
        }

        @Override
        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorRead(gatt, descriptor, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //参考特性的处理
            }
        }

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorWrite(gatt, descriptor, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //反写成功
            }
        }

        @Override
        public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
            super.onReliableWriteCompleted(gatt, status);
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            super.onReadRemoteRssi(gatt, rssi, status);
        }

        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
            super.onMtuChanged(gatt, mtu, status);
        }
    };

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.open:
                openBT();
                break;
            case R.id.close:
                if (mBluetoothAdapter != null) {
                    mBluetoothAdapter.disable();
                    close();
                }
                break;
            case R.id.start:
                if (isCallback1) {
                    scanBleDevices1(true);
                } else {
                    scanBleDevices2(true);
                }
                break;
            case R.id.stop:
                if (isCallback1) {
                    scanBleDevices1(false);
                } else {
                    scanBleDevices2(false);
                }
                break;
            case R.id.mtu:
                mBluetoothGatt.requestMtu(200);
                break;
//            case R.id.callback_type:
//                isCallback1 = !isCallback1;
//                break;
        }
    }

    /**
     * 搜索回调1
     * 不同于传统蓝牙：这里不需要使用广播接收结果，而是使用回调
     */
    class MyLeScanCallback1 implements BluetoothAdapter.LeScanCallback {
        @Override
        public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
            mDeviceAdapter.addDevice(bluetoothDevice);
        }
    }

    /**
     * 搜索回调2
     * 不同于传统蓝牙：这里不需要使用广播接收结果，而是使用回调
     * <p>
     * callbackType:CALLBACK_TYPE_ALL_MATCHES, CALLBACK_TYPE_FIRST_MATCH or CALLBACK_TYPE_MATCH_LOST
     */
    class MyLeScanCallback2 extends ScanCallback {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
            mDeviceAdapter.addDevice(result.getDevice());
        }

        @Override
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            super.onBatchScanResults(results);
            //批量结果
        }
    }
}
